<template>
	<div class="aes">
		<div>
			<el-radio-group v-model="method" size="mini">
				<el-radio-button label="加密"></el-radio-button>
				<el-radio-button label="解密"></el-radio-button>
			</el-radio-group>
		</div>
		<table v-if="method=='加密'">
			<tr>
				<td class="td1"><span>加密字符</span></td>
				<td class="td2">
					<el-input v-model="encryptStr" @input="encryptMethod()" placeholder="请输入加密内容" size="small"></el-input>
				</td>
			</tr>
			<tr>
				<td class="td1"><span>密钥</span></td>
				<td class="td2">
					<el-input v-model="encryptKey" @input="encryptMethod()" placeholder="请输入密钥" size="small"></el-input>
				</td>
			</tr>
			<tr>
				<td class="td1"><span>iv向量</span></td>
				<td class="td2">
					<el-input v-model="encryptIV" @input="encryptMethod()" placeholder="请输入iv向量" size="small"></el-input>
				</td>
				<td class="td3"><el-button type="primary" @click="encryptIVRandom()" size="small">随机</el-button></td>
			</tr>
			<tr>
				<td class="td1"><span>加密方式</span></td>
				<td class="td2">
					<el-radio-group v-model="encryptAesMode" size="mini" @change="encryptMethod()">
						<el-radio-button label="CBC"></el-radio-button>
						<el-radio-button label="CFB"></el-radio-button>
						<el-radio-button label="OFB"></el-radio-button>
						<el-radio-button label="CTR"></el-radio-button>
						<el-radio-button label="ECB"></el-radio-button>
					</el-radio-group>
				</td>
			</tr>
			<tr>
				<td class="td1"><span>加密结果</span></td>
				<td class="td2"><el-input v-model="encryptResult" class="result" placeholder="输出结果" readonly="readonly" size="small"></el-input></td>
			</tr>
		</table>
		<table v-if="method=='解密'">
			<tr>
				<td class="td1"><span>密文</span></td>
				<td class="td2">
					<el-input v-model="decryptStr" @input="decryptMethod()" placeholder="请输入加密内容" size="small"></el-input>
				</td>
			</tr>
			<tr>
				<td class="td1"><span>密钥</span></td>
				<td class="td2">
					<el-input v-model="decryptKey" @input="decryptMethod()" placeholder="请输入密钥" size="small"></el-input>
				</td>
			</tr>
			<tr>
				<td class="td1"><span>iv向量</span></td>
				<td class="td2">
					<el-input v-model="decryptIV" @input="decryptMethod()" placeholder="请输入iv向量" size="small"></el-input>
				</td>
			</tr>
			<tr>
				<td class="td1"><span>解密方式</span></td>
				<td class="td2">
					<el-radio-group v-model="decryptAesMode" size="mini" @change="decryptMethod()">
						<el-radio-button label="CBC"></el-radio-button>
						<el-radio-button label="CFB"></el-radio-button>
						<el-radio-button label="OFB"></el-radio-button>
						<el-radio-button label="CTR"></el-radio-button>
						<el-radio-button label="ECB"></el-radio-button>
					</el-radio-group>
				</td>
			</tr>
			<tr>
				<td class="td1"><span>解密结果</span></td>
				<td class="td2"><el-input v-model="decryptResult" class="result" placeholder="输出结果" readonly="readonly" size="small"></el-input></td>
			</tr>
		</table>
		<div class="tip">
			<div>提示：</div>
			<div>密钥必须是4的倍数位，否则解密时解密结果为空字符串</div>
			<div>IV（Initialization Vector，初始化向量）是一种随机数或固定值，用于与密钥一起作为输入来初始化加密算法的状态。IV 在加密过程中起到一种“混淆”作用，增加了密码算法的安全性和随机性。</div>
		</div>
	</div>
</template>

<script>
	export default {
		data() {
			return {
				method:"加密",
				encryptStr: "",
				encryptKey:"",
				encryptIV:"",
				encryptAesMode: "CBC",
				encryptResult: "",
				decryptStr:"",
				decryptKey:"",
				decryptIV:"",
				decryptAesMode: "CBC",
				decryptResult:"",
			}
		},
		computed:{
			
		},
		methods: {
			encryptMethod(){
				if(this.encryptStr!="" && this.encryptKey!="" && this.encryptIV!=""){
					// 对密钥和向量进行编码
					let keyUtf8 = CryptoJS.enc.Utf8.parse(this.encryptKey);
					let ivUtf8 = CryptoJS.enc.Utf8.parse(this.encryptIV);
					
					let aesMode;
					switch(this.encryptAesMode){
						case "CBC": aesMode = CryptoJS.mode.CBC;
							break;
						case "CFB": aesMode = CryptoJS.mode.CFB;
							break;
						case "OFB": aesMode = CryptoJS.mode.OFB;
							break;
						case "CTR": aesMode = CryptoJS.mode.CTR;
							break;
						case "ECB": aesMode = CryptoJS.mode.ECB;
							break;
					}
					
					let options = {
					    mode: aesMode,	// 采用 xx 分组模式
					    padding: CryptoJS.pad.Pkcs7,	//在对数据进行加密时，需要将数据进行分组处理。如果数据长度不能完全被分组大小整除，则需要进行填充。常见的填充方式包括NoPadding、Pkcs7Padding、Iso10126Padding等。
					    iv: ivUtf8 // 指定初始化向量 IV
					};
					
					let result = CryptoJS.AES.encrypt(this.encryptStr, keyUtf8, options);
					this.encryptResult = result.toString();
				}
			},
			decryptMethod(){
				if(this.decryptStr!="" && this.decryptKey!="" && this.decryptIV!=""){
					// 对密钥和向量进行编码
					let keyUtf8 = CryptoJS.enc.Utf8.parse(this.decryptKey);
					let ivUtf8 = CryptoJS.enc.Utf8.parse(this.decryptIV);
					
					let aesMode;
					switch(this.encryptAesMode){
						case "CBC": aesMode = CryptoJS.mode.CBC;
							break;
						case "CFB": aesMode = CryptoJS.mode.CFB;
							break;
						case "OFB": aesMode = CryptoJS.mode.OFB;
							break;
						case "CTR": aesMode = CryptoJS.mode.CTR;
							break;
						case "ECB": aesMode = CryptoJS.mode.ECB;
							break;
					}
					
					// 解密
					const decrypted = CryptoJS.AES.decrypt(this.decryptStr,keyUtf8,{
						mode: aesMode, // 采用 xx 分组模式
						padding: CryptoJS.pad.Pkcs7, // 解密时采用 Pkcs7 填充
						iv: ivUtf8 // 指定初始化向量 IV
					});
					
					// 解密结果转换为 Utf8 字符串
					const plaintext = decrypted.toString(CryptoJS.enc.Utf8);
					this.decryptResult = plaintext;
				}
			},
			encryptIVRandom(){
				// 产生一个随机的初始化向量 IV
				this.encryptIV = CryptoJS.enc.Base64.stringify(CryptoJS.lib.WordArray.random(16));
			},
			decryptIVRandom(){
				this.decryptIV = CryptoJS.enc.Base64.stringify(CryptoJS.lib.WordArray.random(16));
			},
		},
	}
</script>

<style scoped>
	.aes table{
		table-layout: fixed;
		font-size: 16px;
	}
	.aes table tr td {
		height: 33px;
		text-align: left;
		word-wrap: break-word;
		word-break: break-all;
	}
	.aes .tip {
		font-size: 16px;
		text-align: left;
	}
	.result >>> .el-input__inner{
		background-color: #e5e5e5;
	}
	
	@media screen and (min-width: 1200px){
		.td1{
			width: 110px;
		}
		.td2{
			width: 800px;
		}
	}
	@media screen and (max-width: 1200px){
		.td1{
			width: 110px;
		}		
		.td2{
			width: 450px;
		}
	}
	@media screen and (max-width: 767px){
		.td1{
			width: 75px;
		}
		.td2{
			width: 275px;
			font-size: 14px;
		}
	}
</style>
